﻿using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json.Linq;
using ZH.RetailContainer.RedisLibrary;
using Microsoft.AspNetCore.Antiforgery;
using System.Linq;
using Newtonsoft.Json;
using System;
using ZH.RetailContainer.CommLibrary.Extend;
using ZH.GPT.Utils;
using ZH.GPT.Domains;
using ZH.RetailContainer.CommLibrary;
using ZH.RetailContainer.CommLibrary.Result;

namespace ZH.GPT.CustomFilter
{
    /// <summary>
    /// 防止重复请求
    /// </summary>
    public class CustomRepetitionSubmitAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 日志
        /// </summary>
        ILogger<CustomRepetitionSubmitAttribute> logger;
        /// <summary>
        /// ContentResult
        /// </summary>
        MyContentResult myContentResult;
        /// <summary>
        /// Redis
        /// </summary>
        readonly IRedisService redisService;
        /// <summary>
        /// CustomRepetitionSubmitAttribute
        /// </summary>
        /// <param name="logger">日志</param>
        /// <param name="myContentResult">ContentResult</param>
        /// <param name="redisService">redis</param>
        public CustomRepetitionSubmitAttribute(ILogger<CustomRepetitionSubmitAttribute> logger, MyContentResult myContentResult, IRedisService redisService)
        {
            this.logger = logger;
            this.myContentResult = myContentResult;
            this.redisService = redisService;
        }

        /// <summary>
        /// OnActionExecuted
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {

        }

        /// <summary>
        /// OnActionExecuting
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //IAntiforgery antiforgery = context.HttpContext.RequestServices.GetService(typeof(IAntiforgery)) as IAntiforgery;
            //if (antiforgery == null)
            //    return;
            ////获取请求tokens
            //AntiforgeryTokenSet tokens = antiforgery.GetAndStoreTokens(context.HttpContext);
            //获取参数
            string arguments = JsonConvert.SerializeObject(context.ActionArguments, Formatting.Indented);
            string argumentsMD5Str = EncryptionAndDecryptionHelper.EncryptMD5(arguments);

            string route = context.RouteData.Values["controller"].ToString() + "-" + context.RouteData.Values["action"].ToString();
            string ip = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrWhiteSpace(ip))
                ip = context.HttpContext.Request.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();

            string lockStr = route + "-" + ip + "-" + argumentsMD5Str;
            logger.LogInformation(lockStr);
            try
            {
                if (!redisService.LockNew("RepetitionSubmit:" + lockStr, lockStr, 300))
                {
                    Result<Error> result = PackResult.Pack(ErrorCode.System_RepetitionSubmit);
                    context.Result = myContentResult.Content(result.ToString());
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex.CustomExceptionMessageExtend());
            }
            finally
            {
                //不解锁，因为多次请求可能会岔开，导致锁失效
                //redisService.UnlockNew("RepetitionSubmit:" + lockStr, lockStr);
            }
        }

        /// <summary>  var modelState = context.ModelState;
        /// OnResultExecuting
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuting(ResultExecutingContext context)
        {
        }

        /// <summary>
        /// OnResultExecuted
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }
}
